#include "touch_pad.h"

// #include "driver/gptimer.h"

static const char *TAG = "Touch pad";

uint64_t value = 0;
extern gptimer_handle_t gptimer_handle;
extern int touch_time;
static QueueHandle_t que_touch = NULL;
QueueHandle_t btn_data = NULL;
typedef struct touch_msg
{
    touch_pad_intr_mask_t intr_mask;
    uint32_t pad_num;
    uint32_t pad_status;
    uint32_t pad_val;
} touch_event_t;

btn_struct btn;
touch_status touch_sta;

#define TOUCH_BUTTON_NUM 1

static void btn_state_check(void *pvParameter);

static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
    TOUCH_PAD_NUM4, // 'SELECT' button.
};

static const float button_threshold[TOUCH_BUTTON_NUM] = {
    0.2, // 20%.
};

static void touchsensor_interrupt_cb(void *arg)
{
    int task_awoken = pdFALSE;
    touch_event_t evt;

    evt.intr_mask = touch_pad_read_intr_status_mask();
    evt.pad_status = touch_pad_get_status();
    evt.pad_num = touch_pad_get_current_meas_channel();

    xQueueSendFromISR(que_touch, &evt, &task_awoken);
    if (task_awoken == pdTRUE)
    {
        portYIELD_FROM_ISR();
    }
}

static void tp_example_set_thresholds(void)
{
    uint32_t touch_value;
    for (int i = 0; i < TOUCH_BUTTON_NUM; i++)
    {
        // read benchmark value
        touch_pad_read_benchmark(button[i], &touch_value);
        // set interrupt threshold.
        touch_pad_set_thresh(button[i], touch_value * button_threshold[i]);
        ESP_LOGI(TAG, "touch pad [%d] base %" PRIu32 ", thresh %" PRIu32,
                 button[i], touch_value, (uint32_t)(touch_value * button_threshold[i]));
    }
}

static void touchsensor_filter_set(touch_filter_mode_t mode)
{
    /* Filter function */
    touch_filter_config_t filter_info = {
        .mode = mode,      // Test jitter and filter 1/4.
        .debounce_cnt = 1, // 1 time count.
        .noise_thr = 0,    // 50%
        .jitter_step = 4,  // use for jitter mode.
        .smh_lvl = TOUCH_PAD_SMOOTH_IIR_2,
    };
    touch_pad_filter_set_config(&filter_info);
    touch_pad_filter_enable();
    ESP_LOGI(TAG, "touch pad filter init");
}

static void tp_example_read_task(void *pvParameter)
{
    touch_event_t evt = {0};
    static uint8_t guard_mode_flag = 0;
    /* Wait touch sensor init done */
    vTaskDelay(50 / portTICK_PERIOD_MS);
    tp_example_set_thresholds();

    // 初始化硬件定时器
    // timer_init();
    touch_sta = touch_zero;
    while (1)
    {
        int ret = xQueueReceive(que_touch, &evt, (TickType_t)portMAX_DELAY);
        if (ret != pdTRUE)
        {
            continue;
        }
        if (evt.pad_num == 4)
        {
            if (evt.pad_status == 16) // 按下
            {
                // printf("touch_state:%d\n", touch_sta);
                if (touch_sta == touch_zero) // 如果按键的状态为0，未按下
                {
                    timer_init();
                    ESP_ERROR_CHECK(gptimer_enable(gptimer_handle));           // 使能定时器
                    ESP_ERROR_CHECK(gptimer_start(gptimer_handle));            // 开启定时器
                    ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer_handle, 0)); // 计数清零
                    // ESP_LOGI(TAG, "timer start");
                    touch_sta = touch_one_press;
                }
                if (touch_sta == touch_one_unpress)                // 如果按键的状态为第一次按下并且松开的状态
                {                                                  //
                    gptimer_get_raw_count(gptimer_handle, &value); // 获取计数时间
                    // ESP_LOGI(TAG, "touch timer:%llu", value);                     // 打印两次按键的间隔
                    if (value < 500000)         // 如果时间小于0.5秒
                    {                           //
                        touch_sta = touch_zero; // 按键的状态为第二次按下
                        // ESP_LOGI(TAG, "touch timer:%llu\t%d", value, touch_time); // 打印两次按键的间隔
                        gptimer_stop(gptimer_handle);        // 停止计时器
                        gptimer_disable(gptimer_handle);     // 关闭计时器
                        gptimer_del_timer(gptimer_handle);   // 删除定时器
                        btn.flag = 2;                        // 设置按键的状态
                        btn.touch = touch_sta;               // 将当前的touch状态赋值给结构体
                        xQueueSend(btn_data, &btn, pdFALSE); // 立即发送按键的状态
                    }
                    // ESP_LOGI(TAG, "touch_two_press");
                }
            }
            if (evt.pad_status == 0)                               // 抬起
            {                                                      //
                if (touch_sta == touch_one_press)                  // 如果按键为第一次按下
                {                                                  //
                    gptimer_get_raw_count(gptimer_handle, &value); // 获取按键按下的时间
                    // ESP_LOGI(TAG, "touch timer:%llu", value);      // 打印两次按键的间隔
                    if (value >= 3000000)                    // 如果时间大于3秒
                    {                                        //
                        touch_sta = touch_zero;              // 清除当前的按键状态
                        gptimer_stop(gptimer_handle);        // 停止定时器
                        gptimer_disable(gptimer_handle);     // 关闭定时器
                        gptimer_del_timer(gptimer_handle);   // 删除定时器
                        btn.flag = 3;                        // 设置按键的状态
                        btn.touch = touch_sta;               // 将当前的touch状态赋值给结构体
                        xQueueSend(btn_data, &btn, pdFALSE); // 立即发送按键的状态
                        // ESP_LOGI(TAG, "long press");               // 按下并抬起
                    }
                    else                               // 如果时间小于3秒，
                    {                                  // 则为短按
                        touch_sta = touch_one_unpress; // 将按键的状态设置为第一次按下并抬起
                        // ESP_ERROR_CHECK(gptimer_enable(gptimer_handle));           // 使能定时器
                        // ESP_ERROR_CHECK(gptimer_start(gptimer_handle));            // 开启定时器
                        ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer_handle, 0)); // 计数清零
                        gptimer_alarm_config_t alarm_config =                      // 重新设定报警时间，如果规定的时间内没有触发第二次操作，则认为单击
                            {
                                .alarm_count = 200000, // alarm in next 0.2s
                            };
                        gptimer_set_alarm_action(gptimer_handle, &alarm_config); // 设置报警函数
                        // ESP_LOGI(TAG, "short press");                            //
                    }
                }
                // if (touch_sta == touch_two_press)
                // {
                //     ESP_LOGI(TAG, "touch_two_unpress");
                //     // btn.flag = 2;
                //     // gptimer_stop(gptimer_handle);
                //     // gptimer_disable(gptimer_handle);
                // }

                // gptimer_stop(gptimer_handle);
                // gptimer_disable(gptimer_handle);
                // ESP_LOGI(TAG, "touch timer:%llu\t%d", value, touch_time);
            }
        }
        // ESP_LOGI(TAG, "stat:%d\tintr_mask:%d\tnum::%d\tval:%d", evt.pad_status, evt.intr_mask, evt.pad_num, evt.pad_val);
    }
}

void touch_run(void)
{
    if (que_touch == NULL) // 判断队列是否存在
    {
        que_touch = xQueueCreate(TOUCH_BUTTON_NUM, sizeof(touch_event_t)); // 创建队列
    }
    ESP_LOGI(TAG, "init touch pad");
    touch_pad_init();
    for (int i = 0; i < TOUCH_BUTTON_NUM; i++)
    {
        touch_pad_config(button[i]);
    }

    // 配置降噪功能
    touch_pad_denoise_t denoise = {
        .grade = TOUCH_PAD_DENOISE_BIT4,
        .cap_level = TOUCH_PAD_DENOISE_CAP_L4,
    };
    touch_pad_denoise_set_config(&denoise); // 配置降噪功能
    touch_pad_denoise_enable();             // 启动降噪功能
    ESP_LOGI(TAG, "Denoise function init");

    // 防水功能配置
    touch_pad_waterproof_t waterproof = {
        .guard_ring_pad = button[3],
        .shield_driver = TOUCH_PAD_SHIELD_DRV_L2,
    };
    touch_pad_waterproof_set_config(&waterproof);
    touch_pad_waterproof_enable();
    ESP_LOGI(TAG, "touch pad waterproof init");

    // 滤波设置
    touchsensor_filter_set(TOUCH_PAD_FILTER_IIR_16);
    touch_pad_timeout_set(true, SOC_TOUCH_PAD_THRESHOLD_MAX);
    // 注册触发中断函数
    touch_pad_isr_register(touchsensor_interrupt_cb, NULL, TOUCH_PAD_INTR_MASK_ALL);
    /* 如果您有其他触摸算法，可以在测量后得到测量值,触摸板插入掩码扫描完成”中断已生成. */
    touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT);

    // 启用触摸传感器时钟
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    touch_pad_fsm_start();

    // 创建任务
    xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 4096, NULL, 5, NULL);
    // 创建按键状态检测任务
    xTaskCreate(&btn_state_check, "btn_state_check", 4096, NULL, 5, NULL);
}

MENU_STRUCT menu;
LED_STATUS led;
static void btn_state_check(void *pvParameter)
{
    btn_struct button;
    btn_data = xQueueCreate(10, sizeof(btn_struct));
    if (!btn_data)
    {
        ESP_LOGE(TAG, "创建队列失败");
        return;
    }
    led = LED_OFF;

    while (1)
    {
        int ret = xQueueReceive(btn_data, &button, (TickType_t)portMAX_DELAY);
        if (ret != pdTRUE)
        {
            continue;
        }
        printf("------------------------btn_sta:%d\t%d\n", button.flag, button.touch);
        /*************************************按键设置菜单导航**********************************************/
        switch (button.flag)        // 注意:如果未进入菜单
        {                           // 单机为切换开关灯的状态
        case 1:                     // 如果已经进入了菜单状态
        {                           // 则单机为切换
            if (menu.first == 0)    // 双击为确认
            {                       // 长按为退出
                if (led == LED_OFF) // 由于只有一个按键
                {                   // 设置参数时只能设置完了之后，退出并从新进入菜单设置状态
                    led = LED_ON;
                    ESP_LOGI(TAG, "led on");
                    led_on();
                    break;
                }
                if (led == LED_ON)
                {
                    led = LED_OFF;
                    led_off();
                    ESP_LOGI(TAG, "led off");
                    break;
                }
            }
            if ((menu.first != 0) && (menu.second == 0)) // 如果一级菜单被使能,单机的时候切换一级菜单
            {
                menu.first++;
                if (menu.first >= 4)
                {
                    menu.first = 1;
                }
            }
            if ((menu.first != 0) && (menu.last != 0)) // 如果二级菜单被使能,单机的时候切换二级菜单
            {
                if (menu.first == 1) // 如果一级菜单为1(设置色相界面)
                {
                    menu.second++;
                    if (menu.second >= 360)
                    {
                        menu.second = 1;
                    }
                }
                if (menu.first == 2) // 如果一级菜单为2(设置饱和度)
                {
                    menu.second++;
                    if (menu.second >= 100)
                    {
                        menu.second = 1;
                    }
                }
                if (menu.first == 3) // 如果一级菜单为3(设置亮度)
                {
                    menu.second++;
                    if (menu.second >= 50) // 这里由于电流的限制，最大亮度只设置为50
                    {
                        menu.second = 1;
                    }
                }
            }
        }
        break;
        case 2:
        {
            if (menu.first == 0) // 如果未进入菜单界面，则进入菜单界面
            {
                menu.first = 1;
                break;
            }

            if ((menu.first != 0) && (menu.second == 0)) // 如果一级菜单已被使能，且二级菜单未使能
            {
                menu.second = 1; // 使能二级菜单
                break;
            }

            if ((menu.first != 0) && (menu.second != 0)) // 如果一级菜单已被使能，且二级菜单已使能
            {
                menu.last = 1; // 保存参数
                break;
            }
        }
        break;
        case 3:
        {
            menu.first = 0;
            menu.second = 0;
            menu.last = 0;
            led_on();
            led = LED_ON;
        }
        break;
        default:
            break;
        }

        /*************************************菜单导航UI显示**********************************************/
        if ((menu.first != 0) && (menu.second == 0))
        {
            disp_menu(menu.first, 0, 0);
        }
        if ((menu.first != 0) && (menu.second != 0))
        {
            disp_menu(menu.first, menu.second, 0);
        }
        // if (menu.first == 0)
        // {
        //     led_on();
        //     led = LED_ON;
        // }
        led_refresh();
        printf("------------------------first%d\tsecond:%d\tlase%d\n", menu.first, menu.second, menu.last);
    }
}